//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <bsp.h>
#include <init.h>
#include <regs.h>

#include "timer.h"
#include "ite8172.h"
#include "rtc.h"

uint32_t    PIT_ClockRate;          // unit: HZ
uint32_t    PIT_ClockCycle;         // unit: NS

#define PIT_LATCH   \
    ((uint32_t)((PIT_ClockRate + krn.uTickRate / 2) / krn.uTickRate))

#define IT8172_RTC_ADR_REG  (IT8172_PCI_IO_BASE + IT_RTC_BASE)
#define IT8172_RTC_DAT_REG  (IT8172_RTC_ADR_REG + 1)

static char * rtc_adr_reg = (char*)KSEG1ADDR(IT8172_RTC_ADR_REG);
static char * rtc_dat_reg = (char*)KSEG1ADDR(IT8172_RTC_DAT_REG);

unsigned char it8172_rtc_read_data(char addr)
{
	unsigned char retval;

	*(volatile char*)rtc_adr_reg = addr;
	retval =  (char)*(volatile char*)rtc_dat_reg;
	return retval;
}

void it8172_rtc_write_data(char addr, unsigned char data)
{
	*(volatile char*)rtc_adr_reg = addr;
	*(volatile char*)rtc_dat_reg = data;
}

unsigned long CalR4kOffset()
{
    unsigned long   lCount = 0;
    unsigned int    uFlags;

    read_cp0_register($12, uFlags);
	write_cp0_register($12, uFlags & (~0x00000001));

    /* Start counter exactly on falling edge of update flag */
	while (it8172_rtc_read_data(RTC_REG_A) & RTC_UIP);
	while (!(it8172_rtc_read_data(RTC_REG_A) & RTC_UIP));

	/* Start r4k counter. */
	write_cp0_register($9 /*CP0_COUNT*/, lCount);

	/* Read counter exactly on falling edge of update flag */
	while (it8172_rtc_read_data(RTC_REG_A) & RTC_UIP);
	while (!(it8172_rtc_read_data(RTC_REG_A) & RTC_UIP));

	read_cp0_register($9 /*CP0_COUNT*/, lCount);

	/* restore interrupts */
	if (uFlags & 0x1) {
	    read_cp0_register($12, uFlags);
	    uFlags |= 0x1;
		write_cp0_register($12, uFlags);
	}

	return lCount;
}

EXTERN_C DECL_CODEINIT void CDECL InitPIT()
{
    unsigned int            uFreq;

    /* Set Data mode - binary. */
    it8172_rtc_write_data(RTC_CONTROL,
                        it8172_rtc_read_data(RTC_CONTROL) | RTC_DM_BINARY);

    uFreq = CalR4kOffset();
	uFreq += 500;    /* round */
	uFreq -= uFreq%1000;
	PIT_ClockRate = uFreq;
	PIT_ClockCycle = (1000000000 / PIT_ClockRate);
    uFreq = 2 * uFreq;

	kprintf("CPU frequency %d.%02d MHz\n", uFreq/1000000,
	                                    (uFreq%1000000)*100/1000000);
}

EXTERN_C uint_t CDECL BspGetPITTime()
{
    return 0;
}

EXTERN_C void CDECL BspReloadPIT()
{
    uint32_t    uPitCount;

    uPitCount = PitRead();
    uPitCount += PIT_LATCH;
    PitWrite(uPitCount);
}

